feat: add sync-pyproject target to non-destructively patch pyproject.toml via template.yml#838
feat: add sync-pyproject target to non-destructively patch pyproject.toml via template.yml#838
Conversation
…matting) Co-authored-by: tschm <2046079+tschm@users.noreply.github.com>
|
@copilot: can I have license and readme variables for pyproject section? |
Done in commit pyproject:
license: "MIT" # plain string (PEP 639)
# or table form:
# license:
# text: "MIT"
readme: "README.md"
|
…toml via template.yml Co-authored-by: tschm <2046079+tschm@users.noreply.github.com>
|
@copilot: .rhiza/utils/sync_pyproject.py#L134-L211 Complex Method |
…elpers Co-authored-by: tschm <2046079+tschm@users.noreply.github.com>
Refactored in |
Summary
Adds a
make sync-pyprojecttarget and.rhiza/utils/sync_pyproject.pyutility that non-destructively patches selectedpyproject.tomlfields declared in a new optionalpyproject:section of.rhiza/template.yml. Project-owned fields (name,version,dependencies, etc.) are never touched.Changes
.rhiza/utils/sync_pyproject.py— New stdlib+tomlkitutility that readspyproject:from.rhiza/template.ymland patchespyproject.tomlin-place with comment/formatting preservation. Supports five controlled keys:requires-python→ sets[project].requires-pythonclassifiers→ replaces[project].classifierswholesalelicense→ sets[project].license; accepts a plain string ("MIT", PEP 639) or a mapping ({text: "MIT"}/{file: "LICENSE"}, PEP 517 inline table)readme→ sets[project].readme(string file path, e.g."README.md")tool-sections→ syncs named[tool.*]subtrees from rhiza's ownpyproject.toml.rhiza/utils/sync_pyproject.py(refactor) — Decomposed the monolithic_apply_pyproject_sectioninto five focused per-field helpers (_patch_requires_python,_patch_classifiers,_patch_license,_patch_readme,_patch_tool_sections); the orchestrator is now a thin dispatcher.rhiza/make.d/releasing.mk— Newsync-pyprojecttarget (alongsidebump); supportsDRY_RUN=1andCHECK=1(CI-friendly exit-nonzero-on-drift).rhiza/template-bundles.yml— Addedsync_pyproject.pytocorebundle so it flows to all downstream projectspyproject.toml/.rhiza/requirements/tools.txt— Addedtomlkit>=0.13,<1.0as dev dependency; added totool.deptry.package_module_name_map.rhiza/tests/deps/test_sync_pyproject.py— 27 tests covering: no-op, patching, field preservation,license(string and table forms),readme,--dry-run,--check.rhiza/docs/WORKFLOWS.md— Newpyproject.toml Field Synchronizationsection.rhiza/docs/TEMPLATE_YML_EXAMPLE.md— Annotated example of thepyproject:sectionExample downstream
.rhiza/template.yml:Testing
make testpasses locallymake fmthas been runChecklist
make deptrypasses (no unused or missing dependencies)Original prompt
Summary
Add the ability for rhiza to control selected fields in a downstream project's
pyproject.tomlvia a newpyproject:section in.rhiza/template.yml. This is implemented entirely within rhiza (norhiza-clichanges needed) using a Python utility script and a newmake sync-pyprojecttarget.Background
Currently,
pyproject.tomlis completely excluded from rhiza's sync system — it is project-owned. However, several fields are naturally "rhiza-owned" and drift across downstream projects:requires-python— should match rhiza's supported Python version matrixclassifiers— Python version classifiers should mirror.python-version/requires-python[tool.*]sections like[tool.deptry.package_module_name_map]— currently duplicated manuallyThe idea: extend
.rhiza/template.ymlwith an optionalpyproject:section. A newmake sync-pyprojecttarget reads it and non-destructively patchespyproject.toml, preserving all project-specific fields (name,version,description,authors,dependencies, etc.).Changes Required
1. New utility script:
.rhiza/utils/sync_pyproject.pyA Python script (stdlib only — no
tomlkitdep needed for the basic patch, usestomllibto read and string-based TOML writing to patch) that:.rhiza/template.yml(usingpyyaml, already a dev dep) and extracts thepyproject:sectionpyproject.tomlpyproject:section; never touches anything elsepyproject.tomlpreserving structure as much as possible--dry-runflag to preview changes without writing--checkflag (exits non-zero if changes would be made, for CI)The script should use
tomlkit(which preserves comments and formatting) as the TOML write backend. Addtomlkit>=0.13,<1.0topyproject.toml's[dependency-groups].devand to.rhiza/requirements/tools.txt.Supported
pyproject:keys in template.yml:requires-python— sets[project].requires-pythonclassifiers— replaces[project].classifiersentirely (it's a list rhiza owns)tool-sections— a list of dotted TOML paths (e.g.tool.deptry.package_module_name_map) that are synced wholesale from rhiza's ownpyproject.tomlinto the downstream project'spyproject.tomlThe script must:
name,version,description,authors,keywords,dependencies,[dependency-groups],[project.urls]unless explicitly listed[INFO] No pyproject: section in template.yml, nothing to do.and exit 0 if the section is absent (graceful no-op)[INFO] pyproject.toml is already up to date.if no changes are neededuv run python .rhiza/utils/sync_pyproject.py [--dry-run] [--check]2. New Makefile target in
.rhiza/make.d/releasing.mkAdd a
sync-pyprojecttarget:Add
sync-pyprojectto the.PHONYlist inreleasing.mk.3. Update rhiza's own
.rhiza/template.yml(create it — it doesn't exist in the repo itself)Wait — rhiza skips sync on itself (the
make synctarget checks forjebel-quant/rhizaremote and skips). The.rhiza/template.ymlfile doesn't exist in the repo itself by design. Instead, add a well-documented example as.rhiza/docs/TEMPLATE_YML_EXAMPLE.mdshowing the newpyproject:section.4. Update
.rhiza/template-bundles.ymlAdd
.rhiza/utils/sync_pyproject.pyto thecorebundle'sfileslist (so it syncs to all downstream projects):- .rhiza/utils/sync_pyproject.py5. Update
pyproject.tomlin rhiza itselfAdd
tomlkitto[dependency-groups].dev:Also add it to
[tool.deptry.package_module_name_map]:6. Update
.rhiza/requirements/tools.txtAdd:
7. New test file:
.rhiza/tests/deps/test_sync_pyproject.pyAdd tests that verify:
sync_pyproject.pyexists and is importable / syntax-validpyproject:section is absent fromtemplate.ymlrequires-pythonwhen specifiedclassifierswhen specifiedname,version,description, `dependenc...This pull request was created from Copilot chat.
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.